<?php
/**
 * Created by PhpStorm.
 * User: whwyy
 * Date: 2018/4/24 0024
 * Time: 18:32
 */

namespace BeReborn\Event;


use BeReborn\Base\BaseObject;
use Exception;

/**
 * Class Event
 * @package BeReborn\Event
 */
class Event extends BaseObject
{

	/** @var array */
	private static $events = [];

	/** @var bool */
	public $isValid = true;


	/**
	 * @param $name
	 * @param $callback
	 * @param bool $append
	 * @param bool $isRemove
	 */
	public static function on($name, $callback, $append = false, $isRemove = true)
	{
		if (!isset(static::$events[$name])) {
			static::$events[$name] = [];
		}
		if (!empty(static::$events[$name])) {
			foreach (static::$events[$name] as $event) {
				if ($event[1] == $callback) {
					return;
				}
			}
		}
		if ($append) {
			static::$events[$name][] = [$isRemove, $callback];
		} else {
			array_unshift(static::$events[$name], [$isRemove, $callback]);
		}
	}


	/**
	 * @param $name
	 * @param array $params
	 * @param $event
	 * @return bool|mixed
	 */
	public static function trigger($name, array $params = [], $event = null)
	{
		$events = static::get($name, $event);
		if (empty($events)) {
			if (empty($event)) {
				return false;
			}
			return call_user_func($event, ...$params);
		}

		$result = true;
		if (is_object($event)) {
			$result = call_user_func($events, ...$params);
			static::close($name);
		} else {
			static::forEach($name, $events, $params);
		}
		return $result;
	}

	/**
	 * @param $name
	 * @param $events
	 * @param $params
	 * @return bool|mixed
	 */
	private static function forEach($name, $events, $params)
	{
		$result = true;
		foreach ($events as $key => $_event) {
			$result = call_user_func($_event[1], ...$params);
			if ($result === null) {
				$result = true;
			}
			if ($_event[0]) {
				unset(static::$events[$name][$key]);
			}
			if (!$result) {
				break;
			}
		}
		return $result;
	}


	/**
	 * @param $name
	 * @param null $event
	 * @return bool|mixed
	 */
	public static function get($name, $event = null)
	{
		return static::exists($name, $event, true);
	}


	/**
	 * @param $name
	 * @param null $event
	 * @param bool $isReturn
	 * @return bool|mixed
	 */
	public static function exists($name, $event = null, $isReturn = false)
	{
		if (!isset(static::$events[$name])) {
			return false;
		}
		if (empty($event)) {
			return $isReturn ? static::$events[$name] : true;
		}
		foreach (static::$events[$name] as $_event) {
			if ($event == $_event[1]) {
				return $isReturn ? $event : true;
			}
		}
		return false;
	}


	/**
	 * @param $name
	 * @param null $event
	 */
	public static function close($name, $event = null)
	{
		if (!static::exists($name, $event)) {
			return;
		}
		if (empty($event)) {
			unset(static::$events[$name]);
		} else {
			$events = static::$events[$name];
			foreach ($events as $key => $_event) {
				if ($_event == $event) {
					unset(static::$events[$name][$key]);
				}
			}
		}
	}


	/**
	 * @return array
	 * release all events
	 */
	public static function closeAll()
	{
		return static::$events = [];
	}

}
